Skip to content

Refuse a shell the database, show a screen that ended, and unblock a taken-over sign-in - #289

Merged
davidmckayv merged 2 commits into
mainfrom
fix/act-now-issues
Aug 28, 2026
Merged

Refuse a shell the database, show a screen that ended, and unblock a taken-over sign-in#289
davidmckayv merged 2 commits into
mainfrom
fix/act-now-issues

Conversation

@davidmckayv

@davidmckayv davidmckayv commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Fixes five issues left open after the 0.0.5 triage that were validated as still reproducing on main and in-spirit for the template. Bundled at request; each fix is independent and could be split.

Closes #226, closes #287, closes #275, closes #199.

What each fix does

Verification — honest about depth

Three of these can only be fully proven by a CI image build or a live provider; the agent processes (agent-bot, agent-langgraph, agent-computer) also can't boot in a bare worktree due to workspace dep hoisting. So:

Fix Verified locally Gated to CI
all lint 0, typecheck 0 (all packages), build 0
#226 scram core proven against a real Postgres: with the password select 1 returns 1; without it, and as a non-postgres OS user (the Bot shell's case), the connection is refused. postgres-init.sh parses (sh -n). the s6 wiring (password propagation via with-contenv, persistence across restart) needs the assembled image
#287 typecheck + build + review; renders problem in the mounted branch the live-screen-end state needs agent-computer running
#275 typecheck + review of the launch config the assembled browser's behavior needs the image
#199 typecheck; logic reviewed agent-langgraph unit tests need @langchain/core (CI has it)
#219 test written to the endpoint's real contract the test spawns agent-bot, which needs @ag-ui (CI runs it)

Deliberate deferrals (not silent gaps)

…taken-over sign-in

Five fixes to issues open against 0.0.5, each generic and none vendor-specific:

- The all-in-one image's embedded PostgreSQL moves from trust-auth to scram-sha-256 with a
  generated password, so a Bot's shell can no longer reach the vault/audit as the owner (#226).
- A live screen that ends renders its reason in the branch that is mounted, instead of leaving a
  frozen frame (#287).
- The Bot's browser drops the automation flags that make sites refuse a person's sign-in, at the
  source rather than by patching navigator.webdriver (#275).
- The langgraph Bot carries a continuation turn when a run has no human message, and ends an empty
  reply on a visible line, so strict providers stop failing silently (#199).
- A deterministic acceptance test drives the built-in Bot's authenticated AG-UI contract and asserts
  no secret is disclosed (#219).
The acceptance test spawns agent-bot and could not be run in a bare worktree (workspace
dep resolution), so it went to CI unverified and failed there. Pulling it from this PR;
#219's test half stays open for a change that can be verified before it ships. The four
behavioural fixes remain.
@davidmckayv
davidmckayv merged commit fb0c797 into main Aug 28, 2026
13 checks passed
@davidmckayv
davidmckayv deleted the fix/act-now-issues branch August 28, 2026 17:57
davidmckayv pushed a commit that referenced this pull request Aug 31, 2026
…raph sees (#292)

A reply with no text and no tool call ends the graph — the conditional edge
sees no calls and stops. #289 tried to give that run a visible line by
substituting a fallback AIMessage into the graph's state (withVisibleReply),
so the CHANGELOG already promises "an empty reply ends on a visible line
rather than in silence".

It never reached the person. This service streams AG-UI by reading the run's
framework events, and it emits text only from on_chat_model_stream (the model's
own deltas) and tool events from the tools node. A message a graph node
returns is never one of those, so a fallback placed in state is a fallback the
surface never sees: an empty reply still ended on a bare RUN_STARTED/
RUN_FINISHED pair with nothing between them.

Proof, driving the real reader over a real graph with a fake empty model:
the graph's final state held the fallback, and the client received only
["RUN_FINISHED"].

The guard belongs on the wire, where the surface reads. streamRun now tracks
whether anything a person can see reached it — a line of prose or a tool call —
and ends a run that produced neither on the same fallback line. "Visible" is
decided by textOfChunk, the one rule the streamed deltas already use, so a
reply that is only a Responses-API reasoning summary (text the person is never
shown) counts as empty here too — the case the state-based guard got wrong,
since hasVisibleText read any `text` field as visible.

The translation is extracted to stream.ts for the same reason history.ts and
deltas.ts are: index.ts calls serve() at module scope, so importing runAgent
to test it binds a port. stream.ts imports no runtime module beyond deltas, so
its tests need no provider key and no network.

Co-authored-by: kevin9327 <kevin9327@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant